package com.dylan.channel.v9;

import com.dylan.channel.v9.attribute.AttributeKey;
import com.dylan.channel.v9.channel.Channel;
import com.dylan.channel.v9.factory.ChannelFactory;
import com.dylan.channel.v9.factory.ReflectiveChannelFactory;
import com.dylan.channel.v9.future.ChannelFuture;
import com.dylan.channel.v9.option.ChannelOption;
import com.dylan.util.ObjectUtil;

import java.util.LinkedHashMap;
import java.util.Map;

public abstract class AbstractBootStrap<B extends AbstractBootStrap<B, C>, C extends Channel> {

    volatile EventLoopGroup group;

    protected volatile ChannelFactory<? extends Channel> channelFactory;

    private final Map<ChannelOption<?>, Object> options = new LinkedHashMap<ChannelOption<?>, Object>();
    /**
     * @Author: PP-jessica
     * @Description:在NioServerSocketChannel中传递额数据会暂时存放到这个map中，初始化channel才会把这个map中的数据存放到channel中，channel
     * 当你创建的是NioSocketChannel的时候，这里存储的就是与NioSocketChannel有关的参数
     */
    private final Map<AttributeKey<?>, Object> attrs = new LinkedHashMap<AttributeKey<?>, Object>();

    protected B channel(Class<? extends Channel> clazz) {
        this.channelFactory = new ReflectiveChannelFactory<>(clazz);
        return self();
    }

    final ChannelFuture initAndRegister() {
        Channel channel = channelFactory.newChannel();

        try {
            init(channel);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        //注册ServerSocketChannel
        ChannelFuture channelFuture = group.register(channel);

        return channelFuture;
    }
    private B self() {
        return (B) this;
    }
    final Map<AttributeKey<?>, Object> attrs0() {
        return attrs;
    }
    /**
     * @Author: PP-jessica
     * @Description:初始化channel的方法，这里定义为抽象的，意味着客户端channel和服务端channel实现的方法各不相同
     */
    abstract void init(Channel channel) throws Exception;


    public <T> B option(ChannelOption<T> option, T value) {
        ObjectUtil.checkNotNull(option, "text");
        synchronized (options) {
            if (value == null) {
                options.remove(option);
            } else {
                options.put(option, value);
            }
        }
        return self();
    }

    final Map<ChannelOption<?>, Object> options0() {
        return options;
    }
}
